const config = require('./config')

//region helper

/**
 * 小程序自动更新
 */
function autoUpdate() {
  const updateManager = wx.getUpdateManager()
  updateManager.onCheckForUpdate(res => {
    if (res.hasUpdate === false) return

    updateManager.onUpdateReady(() => {
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好，是否重启应用？'
      }).then(res => {
        if (res.confirm) {
          updateManager.applyUpdate()
        }
      })
    })
    updateManager.onUpdateFailed(() => {
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好，请删除当前小程序，重新搜索打开'
      })
    })
  })
}

/**
 * 获取主页路径
 * @return {string}
 */
function getHomePagePath() {
  const pages = getCurrentPages()
  return _getPagePath(pages[0], false)
}

/**
 * 获取当前页面路径
 * @param includeArgs 是否包含页面参数,默认不包含
 * @return {string}
 */
function getCurrentPagePath(includeArgs = false) {
  const pages = getCurrentPages()
  const currentPage = pages[pages.length - 1]
  return _getPagePath(currentPage, includeArgs)
}

/**
 * 获取当前页面路径
 * @param page 页面对象
 * @param includeArgs 是否包含页面参数
 * @return {string}
 */
function _getPagePath(page, includeArgs) {
  const url = page.route
  const distUrl = `/${url}`
  if (includeArgs === false) {
    return distUrl
  }
  const options = page.options
  const objKeys = Object.keys(options)
  if (objKeys.length === 0) return distUrl

  let urlWithArgs = distUrl + '?'
  for (let i = 0; i < objKeys.length; i++) {
    const key = objKeys[i]
    const value = options[key]
    urlWithArgs += `${key}=${value}&`
  }
  urlWithArgs = urlWithArgs.substring(0, urlWithArgs.length - 1)
  return urlWithArgs
}

/**
 * 授权
 * <p>
 *   授权 scope.userLocation、scope.userLocationBackground 时必须配置地理位置用途说明,在app.json中配置permission节点
 * </p>
 * @param scopeCode {'scope.userLocation'|'scope.userLocationBackground'|'scope.werun'|'scope.record'|'scope.writePhotosAlbum'|'scope.camera'} 权限编码
 * @param confirmMsg {string} 确认消息
 * @return {Promise}
 */
function authorize(scopeCode, confirmMsg) {
  return new Promise(async (resolve, reject) => {
    wx.authorize({
      scope: scopeCode,
      success() {
        resolve({})
      },
      fail() {
        wx.showModal({
          title: '系统提示',
          content: confirmMsg,
          success(res) {
            if (res.confirm) {
              wx.openSetting({
                success(osres) {
                  if (osres.authSetting[scopeCode] === true) {
                    resolve({})
                  } else {
                    _showAuthorizeDenyToast()
                  }
                },
                fail(err) {
                  console.log('wx.openSetting fail', err)
                  reject(err)
                }
              })
            } else {
              _showAuthorizeDenyToast()
            }
          },
          fail(err) {
            reject(err)
          }
        })
      }
    })
  })
}

function _showAuthorizeDenyToast() {
  const title = '拒绝授权,当前功能将无法正常使用'
  wx.showToast({
    title: title,
    icon: 'none',
    duration: 3000
  })
}


/**
 * 显示消息提示框
 * @param msg {string} 提示的内容
 * @return {Promise}
 */
function showToast(msg) {
  return wx.showToast({
    title: msg,
    icon: 'none',
    mask: false,
    duration: 2000
  })
}

/**
 * 隐藏消息提示框
 * @return {Promise}
 */
function hideToast() {
  return wx.hideToast()
}

/**
 * 下划线转换驼峰
 */
function lineToHump(name) {
  return name.replace(/_(\w)/g, function (all, letter) {
    return letter.toUpperCase()
  })
}

/**
 * 驼峰转换下划线
 */
function humpToLine(name) {
  return name.replace(/([A-Z])/g, '_$1').toLowerCase()
}

/**
 * 创建UUID.(Universally Unique Identifier 通用唯一识别码)
 * @return {string}
 */
function uuid() {
  return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    const r = Math.random() * 16 | 0,
            v = c === 'x' ? r : (r & 3 | 8)
    return v.toString(16)
  }).toLowerCase()
}

/**
 * 生成随机数字(min-max之间)
 * @param {number} min 最小值
 * @param {number} max 最大值
 * @return {number}
 */
function randomNumber(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min
}

/**
 * 生成随机字符串
 * @param {number} len 字符串总长度
 * @return {string}
 */
function randomString(len) {
  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let str = ''
  for (let i = 0; i < len; ++i) {
    const rand = Math.floor(Math.random() * alphabet.length)
    str += alphabet.substring(rand, rand + 1)
  }
  return str
}

/**
 * 获取固定长度的字符串
 * @param {string} str 原始字符串
 * @param {number} total 字符串总长度
 * @param {string} [defaults='0'] 默认补充字符
 */
function fixLenString(str, total, defaults) {
  str = str.toString()
  if (typeof defaults === 'undefined') {
    defaults = '0'
  }
  let result = ''
  const times = total - (str.length)
  for (let i = 1; i <= times; i++) {
    result = defaults + result
  }
  return result + str
}

/**
 * 格式化为日期
 * @param {Date} date 日期
 * @param {string} format 格式
 * @return {string}
 * @example jx.formatDate(new Date('2014/07/10 10:21:12'),'MM-dd')
 */
function formatDate(date, format = 'yyyy-MM-dd') {
  if (typeof date === 'string' && date) {
    date = new Date(date.toString().replace('-', '/'))
  }
  if (typeof format === 'undefined') {
    format = 'yyyy-MM-dd'
  }
  const o = {
    'M+': date.getMonth() + 1,                  //month
    'd+': date.getDate(),                       //day
    'h+': date.getHours(),                      //hour
    'm+': date.getMinutes(),                    //minute
    's+': date.getSeconds(),                    //second
    'q+': Math.floor((date.getMonth() + 3) / 3),//quarter
    'S': date.getMilliseconds() //millisecond
  }
  if (/(y+)/.test(format)) {
    format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  for (const k in o) {
    if (new RegExp('(' + k + ')').test(format)) {
      format = format.replace(RegExp.$1,
              RegExp.$1.length === 1 ? o[k] :
                      ('00' + o[k]).substr(('' + o[k]).length))
    }
  }
  return format
}

/**
 * 格式化为标准日期时间
 * @param {Date} date
 */
function formatDateTime(date) {
  return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
}

/**
 * 格式化为标准时间
 * @param {Date} date
 */
function formatTime(date) {
  return formatDate(date, 'hh:mm:ss')
}

/**
 * 日期计算，添加天数到指定日期
 * @param date 日期
 * @param days 天数
 */
function addDate(date, days) {
  const n = date.setDate(date.getDate() + days)
  return new Date(n)
}

/**
 * 日期比较
 * 如果开始日期大于结束日期,返回1
 * 如果开始日期等于结束日期,返回0
 * 如果开始日期小于结束日期,返回-1
 * @return {number}
 */
function compareDate(startDateStr, endDateStr) {
  const _startDate = new Date(startDateStr.replace(/[-.,]/g, '/'))
  const _endDate = new Date(endDateStr.replace(/[-.,]/g, '/'))
  if (_startDate > _endDate) return 1
  if (_startDate < _endDate) return -1
  return 0
}

/**
 * 判断值是否为空
 * @param value 值
 * @return {boolean}
 * @private
 */
function isBlank(value) {
  return value === undefined || value === null || value === ''
}

/**
 * 倒计时
 * @param count 从即开始
 * @param callback 每执行一次的回调函数
 */
function countDown(count, callback) {
  function _core() {
    callback(count)
    if (count > 0) {
      count--
      setTimeout(function () {
        _core()
      }, 1000)
    }
  }

  _core()
}

/**
 * 函数节流
 * 单位时间n秒内，第一次触发函数并执行，以后 n秒内不管触发多少次，都不执行。直到下一个单位时间n秒，第一次触发函数并执行，这个n秒内不管函数多少次都不执行。
 */
function throttle(fn, interval) {
  let enterTime = 0;//触发的时间
  let gapTime = interval || 300 ;//间隔时间，如果interval不传，则默认300ms
  return function() {
    let context = this;
    let backTime = new Date();//第一次函数return即触发的时间
    if (backTime - enterTime > gapTime) {
      fn.call(context,arguments);
      enterTime = backTime;//赋值给第一次触发的时间，这样就保存了第二次触发的时间
    }
  };
}

/**
 * 函数防抖
 * 延迟函数执行。即不管debounce函数触发了多久，只在最后一次触发debounce函数时，才定义setTimeout，到达间隔时间再执行 需要防抖的函数。
 */
function debounce(fn, interval) {
  let timer;
  let gapTime = interval || 1000;//间隔时间，如果interval不传，则默认1000ms
  return function() {
    clearTimeout(timer);
    let context = this;
    let args = arguments;//保存此处的arguments，因为setTimeout是全局的，arguments不是防抖函数需要的。
    timer = setTimeout(function() {
      fn.call(context,args);
    }, gapTime);
  };
}

//endregion

//region uploadFile

/**
 * 封装上传多个文件
 * @param filePaths {Array<string>} 要上传文件资源的路径 (本地路径)数组
 * @param [virtualCatalog] {string} 服务端虚拟目录
 * @param [loading] {string} load提示文本,如果为null或者false则不显示
 * @return {Promise<Object>}
 */
function uploadFiles(filePaths, virtualCatalog = '', loading = '正在上传...') {
  if (!filePaths || filePaths.length === 0) return Promise.reject('请指定要上传的文件数组')

  if (loading) {
    wx.showLoading({
      title: loading,
      mask: true
    })
  }

  const results = []
  for (let i = 0; i < filePaths.length; i++) {
    const result = _uploadFile(filePaths[i], virtualCatalog)
    results.push(result)
  }

  return Promise.all(results).finally(() => {
    if (loading) wx.hideLoading()
  })
}

/**
 * 封装上传单个文件
 * @param filePath 要上传文件资源的路径 (本地路径)
 * @param virtualCatalog 服务端虚拟目录
 * @return {Promise<Object>}
 */
function _uploadFile(filePath, virtualCatalog = '') {
  return new Promise((resolve, reject) => {
    wx.uploadFile({
      url: config.getApiUrl(config.uploadFileApiUrl),
      filePath: filePath,
      name: 'file',
      header: {...config.getDefaultHeader()},
      formData: {virtualCatalog},
      success(res) {
        resolve(JSON.parse(res.data))
      },
      fail(err) {
        console.error('upload file fail', err)
        reject(err)
      }
    })
  })
}

/**
 * 生成 UploadFile URL
 * @param fileUrl 文件地址
 * @return {string} 请求URL
 */
function buildUploadFileUrl(fileUrl) {
  if (fileUrl.indexOf('://') === -1) {
    fileUrl = config.baseUrl + fileUrl
  }
  return fileUrl
}

//endregion

module.exports = {
  autoUpdate,
  getHomePagePath,
  getCurrentPagePath,
  authorize,
  uploadFiles,
  buildUploadFileUrl,
  lineToHump,
  humpToLine,
  fixLenString,
  uuid,
  isBlank,
  randomNumber,
  randomString,
  formatDate,
  formatDateTime,
  formatTime,
  addDate,
  showToast,
  hideToast,
  compareDate,
  countDown,
  throttle,
  debounce
}
